#include "gzip.h"

/*
 *@gzip 头部;
 */
static const char gzipHeader[] = { 0x1F, 0x8B, Z_DEFLATED, 1, 1, 1, 1, 1, 1, 0x03 };

/*
 *@构建gzip的尾部;
 */
void addGzipTail(unsigned char *tail, unsigned long data){
	tail[0] = (data & 0xff);
	tail[1] = ((data >> 8 ) & 0xff);
	tail[2] = ((data >> 16) & 0xff);
	tail[3] = ((data >> 24) & 0xff);
}


/*
 *@brief:初始化gzip option:
 */
int gzipInit(z_stream  *stream){
	int iRet = RET_ERROR;
	INIT_GZIP_STREAM(stream);
	iRet = deflateInit2(stream, Z_BEST_SPEED, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
	if(iRet != Z_OK){
		fprintf(stderr, "[error]gzip option init failure!\n");
		return iRet;
	}
	return RET_OK;
}

/*
 *@compress data
 */
int gzipData(z_stream *stream, unsigned char *out, size_t outMaxLen, unsigned char *in, size_t dataLen){
#define GZIP_HEADER_LEN   10
	int iRet = RET_ERROR;
	unsigned compressLen;
	if(!out || !in){
		fprintf(stderr, "[error]get unavaliable args in [func]:%s [line]:%d\n", __func__,__LINE__);
		return iRet;
	}
	/*
	 *先拷贝gzip头部;
	 */
	memcpy(out, gzipHeader, GZIP_HEADER_LEN);
	stream->avail_in = dataLen;
	stream->next_in =  in;
	stream->avail_out = outMaxLen;
	stream->next_out = out + GZIP_HEADER_LEN;
	iRet = deflate(stream, Z_FINISH);
	switch(iRet){
		case Z_NEED_DICT:
			iRet = Z_DATA_ERROR;
		case Z_DATA_ERROR:
		case Z_MEM_ERROR:
			(void)inflateEnd(stream);
			return iRet;
	}
	compressLen = outMaxLen - stream->avail_out;
	unsigned crc = crc32(0L, in, dataLen);
	unsigned char *tail = out + GZIP_HEADER_LEN + compressLen;
	/*
	 *@构造gzip的尾部
	 */
	addGzipTail(tail, crc);
	addGzipTail(tail + 4, dataLen);
	deflateEnd(stream);
	return compressLen;
}

